package com.easy.project.service.common.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easy.project.base.exception.ServiceException;
import com.easy.project.base.result.SystemErrorCodeEnum;
import com.easy.project.config.file.FileConfig;
import com.easy.project.constant.FileServiceTypeEnum;
import com.easy.project.convert.FileDomainConvert;
import com.easy.project.domain.dto.common.SysFileDTO;
import com.easy.project.domain.po.system.SysFilePO;
import com.easy.project.domain.vo.common.SysFileVO;
import com.easy.project.mapper.system.SysFileMapper;
import com.easy.project.service.common.ISysFileService;
import com.easy.project.util.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

import static com.easy.project.base.result.SystemErrorCodeEnum.FILE_UPLOAD_ERROR;

/**
 * 本地文件存储 文件的实现类
 */
@Slf4j
@Service
@ConditionalOnProperty(name = "file.type",havingValue = "LOCAL")
public class LocalFileServiceImpl extends ServiceImpl<SysFileMapper, SysFilePO> implements ISysFileService {

    @Resource
    private FileConfig fileConfig;

    @Resource
    private FileDomainConvert fileDomainConvert;

    @PostConstruct
    public void init(){
        log.info("文件本地服务加载成功");
    }

    @Override
    public String getType() {
        return FileServiceTypeEnum.LOCAL.getCode();
    }

    @Override
    public SysFileVO upload(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        String onlyFileName = FileUtils.changeFileName(Objects.requireNonNull(originalFilename));
        try {
            file.transferTo(new File(fileConfig.getLocalStorePath() + onlyFileName));
        } catch (IOException e) {
            log.error("上传文件失败：", e);
            throw new ServiceException(FILE_UPLOAD_ERROR);
        }
        // 保存文件信息
        SysFilePO sysFilePO = new SysFilePO();
        // 本地文件的fileKey使用uuid
        sysFilePO.setFileKey(UUID.randomUUID().toString());
        sysFilePO.setFileType(FileServiceTypeEnum.LOCAL.getCode());
        sysFilePO.setFileStoreName(onlyFileName);
        sysFilePO.setFileRealName(originalFilename);
        boolean save = save(sysFilePO);
        if (!save){
            log.error("保存文件到数据库失败参数：{}", JSONUtil.toJsonStr(sysFilePO));
            throw new ServiceException(FILE_UPLOAD_ERROR);
        }
        // 组装结果集
        SysFileVO sysFileVO = fileDomainConvert.poToVo(sysFilePO);
        sysFileVO.setPreviewUrl(getPreviewUrl(onlyFileName));
        return sysFileVO;
    }

    @Override
    public List<SysFileVO> getUrlList(SysFileDTO sysFileDTO) {
        List<String> fileKeyList = sysFileDTO.getFileKeyList();
        List<SysFilePO> sysFilePOList = list(new LambdaQueryWrapper<SysFilePO>().in(SysFilePO::getFileKey, fileKeyList));
        List<SysFileVO> sysFileVOList = fileDomainConvert.poListToVoList(sysFilePOList);
        for (SysFileVO sysFileVO : sysFileVOList){
            sysFileVO.setPreviewUrl(getPreviewUrl(sysFileVO.getFileStoreName()));
        }
        return sysFileVOList;
    }

    private String getPreviewUrl(String fileStoreName){
        return fileConfig.getLocalPreviewUrl() + fileStoreName;
    }

    @Override
    public void download(String fileKey, HttpServletResponse response) {
        SysFilePO sysFilePO = getOne(new LambdaQueryWrapper<SysFilePO>().eq(SysFilePO::getFileKey, fileKey));
        try (InputStream inputStream = new FileInputStream(fileConfig.getLocalStorePath() + sysFilePO.getFileStoreName())) {
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
                while ((len = inputStream.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                response.setCharacterEncoding("utf-8");
                // 设置强制下载不打开
                // res.setContentType("application/force-download");
                response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(sysFilePO.getFileRealName(), StandardCharsets.UTF_8));
                try (ServletOutputStream stream = response.getOutputStream()) {
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            log.error("文件下载 错误：", e);
            throw new ServiceException(SystemErrorCodeEnum.FILE_DOWNLOAD_ERROR);
        }

    }

}
